/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.web.gwt.form.client.widget.item.impl;

import java.util.List;

import com.genia.toolbox.web.gwt.basics.client.GwtHelper;
import com.genia.toolbox.web.gwt.basics.client.i18n.GwtI18nMessage;
import com.genia.toolbox.web.gwt.basics.client.support.GwtObjectUtils;
import com.genia.toolbox.web.gwt.form.client.CssNames;
import com.genia.toolbox.web.gwt.form.client.form.RadioButtonInterface;
import com.genia.toolbox.web.gwt.form.client.form.ValuedItemEntry;
import com.genia.toolbox.web.gwt.form.client.widget.item.ItemWidgetModifyListener;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * <code>SimpleItemWidget</code> to represents a group of radio.
 * 
 * @param <ITEM>
 *          the type of item handled by this widget.
 */
public abstract class AbstractRadioButtonItemWidget<ITEM extends RadioButtonInterface>
    extends AbstractSimpleValuedItemWidget<ITEM>
{
  /**
   * the group of buttons that represents this item.
   */
  private transient ValuedRadioButton[] radioButtons;

  /**
   * the list of all the <code>Widget</code> that must be modify to update the
   * error message.
   */
  private transient Widget[] widgetsToToggle;

  /**
   * the value to set once the initialization is done.
   */
  private transient String valueToSet;

  /**
   * the main panel of this widget.
   */
  private transient Panel panel;

  /**
   * the registered listeners.
   */
  private ItemWidgetModifyListenerCollection itemWidgetModifyListenerCollection = new ItemWidgetModifyListenerCollection();

  /**
   * an int that serve as unique identifier for radio group to prevent collision
   * when using multiple sub forms.
   */
  private static int radioGroupUniqueIdentifier = 0;

  /**
   * the unique identifier for the current radioGroup.
   */
  private final int currentRadioGroupUniqueIdentifier;



  /**
   * setting the different values of this item.
   * 
   * @param item
   *          the {@link RadioButtonInterface} representing this object
   * @param valuedItemEntrys
   *          the entries of this item
   */
  protected void setValuedItemEntrys(final RadioButtonInterface item, final List<ValuedItemEntry> valuedItemEntrys)
  {
    String radioGroupName = "i" + currentRadioGroupUniqueIdentifier + "_" + item.getName();
    final ClickListener clickListener = new ClickListener()
    {
      public void onClick(Widget widget)
      {
        itemWidgetModifyListenerCollection.onModify(AbstractRadioButtonItemWidget.this);
      }
    };

    radioButtons = new ValuedRadioButton[valuedItemEntrys.size()];
    widgetsToToggle = new Widget[1 + radioButtons.length];
    // get the 18nMessages from subLabels and set to the radioButton widget.
    int index = 0;
    for (final ValuedItemEntry entry : valuedItemEntrys) {
      radioButtons[index] = new ValuedRadioButton(radioGroupName, entry.getValue());

      GwtHelper.fillText(radioButtons[index], entry.getLabel());

      radioButtons[index].setEnabled(item.isEnabled());

      // set the group of radios to the panel.
      panel.add(radioButtons[index]);
      widgetsToToggle[index] = radioButtons[index];
      radioButtons[index].addClickListener(clickListener);
      index++;
    }
    widgetsToToggle[radioButtons.length] = panel;
    setValue(valueToSet);
  }



  /**
   * returns the suitable value for the currentRadioGroupUniqueIdentifier
   * property.
   * 
   * @return the suitable value for the currentRadioGroupUniqueIdentifier
   *         property.
   */
  private int initCurrentRadioGroupUniqueIdentifier()
  {
    synchronized (AbstractRadioButtonItemWidget.class) {
      return ++radioGroupUniqueIdentifier;
    }
  }



  /**
   * constructor.
   * 
   * @param item
   *          the item that this widget represents.
   */
  public AbstractRadioButtonItemWidget(final ITEM item)
  {
    super(item);
    currentRadioGroupUniqueIdentifier = initCurrentRadioGroupUniqueIdentifier();
    // get parameters from radioButtonItem.
    final GwtI18nMessage labelKey = item.getLabelKey();
    final boolean verticalDisplay = item.isVerticalDisplay();

    // check if radioButtons are display in a vertical way or horizontal way.
    if (verticalDisplay) {
      panel = new VerticalPanel();
    }
    else {
      panel = new HorizontalPanel();
    }

    widgetsToToggle = new Widget[1];
    widgetsToToggle[0] = panel;

    // label associated to the radioButton.
    final Label labelRadio = new Label();

    // set the labelKey to the labelRadio.
    GwtHelper.fillText(labelRadio, labelKey);

    // set the the labelRadio to the panel.
    panel.add(labelRadio);

    // set the style name
    panel.addStyleName(CssNames.RADIO_PANEL_CSS_STYLE);
    panel.addStyleName(item.getName());

    initWidget(panel);
  }



  /**
   * getter for the widgetsToToggle property.
   * 
   * @return the widgetsToToggle
   */
  @Override
  protected Widget[] getWidgetsToToggle()
  {
    return widgetsToToggle;
  }



  /**
   * return the value of this group of button, which is the value of the button
   * currently checked.
   * 
   * @return the current value of the group of buttons.
   */
  @Override
  public String getValue()
  {
    if (radioButtons == null) {
      return null;
    }
    for (ValuedRadioButton radioButton : radioButtons) {
      if (radioButton.isChecked()) {
        return radioButton.getValue();
      }
    }
    return null;
  }



  /**
   * add a listener that is called each time the value of this object change.
   * 
   * @param modifyListener
   *          the callback
   */
  public void addModifyListener(final ItemWidgetModifyListener modifyListener)
  {
    itemWidgetModifyListenerCollection.add(modifyListener);
  }



  /**
   * set the current value of the group of buttons.
   * 
   * @param value
   *          the current value of the group of buttons
   */
  @Override
  public void setValue(final String value)
  {
    if (radioButtons == null) {
      valueToSet = value;
    }
    else {
      for (ValuedRadioButton radioButton : radioButtons) {
        radioButton.setChecked(GwtObjectUtils.nullSafeEquals(value, radioButton.getValue()));
      }
    }
  }

}
